/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
    Stmt,
    ArkFile,
    ClassSignature,
    MethodSignature,
    ArkAssignStmt,
    FieldSignature,
    FileSignature,
    NamespaceSignature,
    AbstractBinopExpr,
    ArkClass,
    ArkMethod,
    ArkField,
    MethodSubSignature,
    Local,
} from 'arkanalyzer/lib';
import { MethodParameter } from 'arkanalyzer/lib/core/model/builder/ArkMethodBuilder';

import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { BaseChecker, BaseMetaData } from '../BaseChecker';
import { Defects, IssueReport } from '../../model/Defects';
import {
    FileMatcher,
    MatcherCallback,
    MatcherTypes,
} from '../../matcher/Matchers';
import { Rule } from '../../model/Rule';
import { RuleListUtil } from '../../utils/common/DefectsList';
import { CheckerUtils } from '../../utils/checker/CheckerUtils';
const defaultOptions: Options = {
    ignoreStatic: false,
};
interface Options {
    /** Whether to skip checking whether `static` methods are correctly bound. */
    ignoreStatic?: boolean;
};
type stmtType = {
    classSignature?: ClassSignature;
    methodSignature?: MethodSignature;
    realGenericTypes: string[];
};
type stmtRightOp = {
    base: {
        constFlag: boolean;
        declaringStmt: Stmt;
        name: string;
        originalValue: string;
        type: stmtType;
        usedStmts: ArkAssignStmt[];
    };
    fieldSignature: FieldSignature;
};
type fieldSignature = {
    fieldSignature: FieldSignature;
};
type rightOpType = {
    fieldSignature: FieldSignature;
};
type declaringSignature = {
    className: string;
    declaringFileSignature: FileSignature;
    declaringNameSpaceSignature: NamespaceSignature;
};
type LeftOp = {
    constFlag: boolean;
    declaringStmt: Stmt;
    name: string;
    originalValue: string;
    type: stmtType;
    usedStmts: ArkAssignStmt[];
};
const logger = Logger.getLogger(
    LOG_MODULE_TYPE.HOMECHECK,
    'UnboundMethodCheck'
);
const gmetaData: BaseMetaData = {
    severity: 2,
    ruleDocPath: 'docs/unbound-method-check.md', // TODO: support url
    description:
        'Avoid referencing unbound methods which may cause unintentional scoping of `this`.If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead. ',
};
export class UnboundMethodCheck implements BaseChecker {
    readonly metaData: BaseMetaData = gmetaData;
    public rule: Rule;
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];
    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
    };

    public registerMatchers(): MatcherCallback[] {
        const matchClass: MatcherCallback = {
            matcher: this.fileMatcher,
            callback: this.check,
        };
        return [matchClass];
    }
    public check = (file: ArkFile): void => {
        // 将规则选项转换为Options类型
        let options: Options;
        if (this.rule && this.rule.option.length > 0) {
            options = this.rule.option[0] as Options;
        } else {
            options = defaultOptions;
        }
        this.processUnboundMethodCheck(file, options);
    };
    private processUnboundMethodCheck(file: ArkFile, options: Options): void {
        const classNameArray: string[] = [];
        const methodNameArray: string[] = [];
        const ExtendmethodNameArray: string[] = [];
        const fieldNameArray: string[] = [];
        const objectNameArray: string[] = [];
        const objectMethodNameArray: string[] = [];

        for (const arkClass of file.getClasses()) {
            this.processClassInitialization(file, arkClass);
            this.collectClassNames(arkClass, classNameArray);
            this.handleCategoryFive(arkClass, objectNameArray, objectMethodNameArray);

            const { methods, fileds } = this.getClassMethodsAndFields(arkClass);
            this.processClassMethodsAndFields(methods, options, file, fileds, methodNameArray, fieldNameArray);
            this.handleDeclaringArkFileClasses(arkClass, file, options, fieldNameArray, ExtendmethodNameArray,
                methodNameArray, classNameArray, objectNameArray, objectMethodNameArray);
        }
    }

    private processClassInitialization(file: ArkFile, arkClass: ArkClass): void {
        if (!arkClass.getCode()) {
            this.processImportsAndAnalyzeStatements(file, arkClass);
        }
    }

    private collectClassNames(arkClass: ArkClass, classNameArray: string[]): void {
        const className = arkClass.getSignature().getClassName();
        if (className && !className.startsWith('%')) {
            classNameArray.push(className);
        }
    }

    private handleCategoryFive(arkClass: ArkClass, objectNameArray: string[],
        objectMethodNameArray: string[]): void {
        if (arkClass.getCategory() === 5) {
            this.processCategoryFive(arkClass, objectNameArray, objectMethodNameArray);
        }
    }

    private getClassMethodsAndFields(arkClass: ArkClass): { methods: ArkMethod[], fileds: ArkField[] } {
        return {
            methods: arkClass.getMethods(),
            fileds: arkClass.getFields()
        };
    }

    private processClassMethodsAndFields(methods: ArkMethod[], options: Options, file: ArkFile,
        fileds: ArkField[], methodNameArray: string[], fieldNameArray: string[]): void {
        this.processMethods(methods, options, file, fileds, methodNameArray, fieldNameArray);
    }

    private handleDeclaringArkFileClasses(arkClass: ArkClass, file: ArkFile, options: Options,
        fieldNameArray: string[], ExtendmethodNameArray: string[], methodNameArray: string[],
        classNameArray: string[], objectNameArray: string[], objectMethodNameArray: string[]): void {
        const declaringArkFile = arkClass.getDeclaringArkFile();
        this.processUnboundMethodCheck1(
            file,
            options,
            fieldNameArray,
            declaringArkFile.getClasses(),
            ExtendmethodNameArray,
            methodNameArray,
            classNameArray,
            objectNameArray,
            objectMethodNameArray,
            arkClass.getCategory(),
            arkClass.getMethods(),
            arkClass
        );
    }
    private processUnboundMethodCheck1(file: ArkFile, options: Options, fieldNameArray: string[], classes: ArkClass[],
        ExtendmethodNameArray: string[], methodNameArray: string[], classNameArray: string[],
        objectNameArray: string[], objectMethodNameArray: string[], category: number, methods: ArkMethod[], arkClass: ArkClass): void {
        if (fieldNameArray.length === 0) {
            for (const targetClass of classes) {
                const ClassSignature = targetClass.getSignature();
                const ClassName = ClassSignature.getClassName();
                const extendedClasses = targetClass.getExtendedClasses();
                this.processExtendedClasses(
                    extendedClasses,
                    ExtendmethodNameArray,
                    file,
                    targetClass
                );
                this.processClass(
                    targetClass,
                    file,
                    methods,
                    classNameArray,
                    methodNameArray,
                    objectNameArray,
                    classes,
                    category,
                    arkClass,
                    objectMethodNameArray,
                    options
                );
            }
        } else {
            this.processClassMethods(
                classes, objectNameArray, objectMethodNameArray, classNameArray, fieldNameArray, methodNameArray, category
            );
        }
    }
    private processClassMethods(classes: any[], objectNameArray: string[], objectMethodNameArray: string[],
        classNameArray: string[], fieldNameArray: string[], methodNameArray: string[], category: number): void {
        for (const Class of classes) {
            const className = this.getClassName(Class);
            if (className.startsWith('%')) {
                this.processDefaultArkMethod(Class, objectNameArray, objectMethodNameArray, classNameArray,
                    fieldNameArray, methodNameArray, category);
            }
        }
    }

    private getClassName(Class: any): string {
        const ClassSignature = Class.getSignature();
        return ClassSignature.getClassName();
    }

    private processDefaultArkMethod(arkClass: ArkClass, objectNameArray: string[], objectMethodNameArray: string[],
        classNameArray: string[], fieldNameArray: string[], methodNameArray: string[], category: number): void {
        const defaultMethod = arkClass.getDefaultArkMethod();
        const stmts = defaultMethod?.getBody()?.getLocals() ?? [];
        for (const [key, value] of stmts.entries()) {
            if (this.shouldSkipStmt(key, value)) {
                continue;
            }

            const type = value.getType() as unknown as stmtType;
            const typeClassSignature = type.classSignature;

            if (typeClassSignature) {
                this.processTypeClassSignature(value, typeClassSignature, objectNameArray,
                    objectMethodNameArray, classNameArray, arkClass, fieldNameArray, methodNameArray, category);
            }
        }
    }

    private shouldSkipStmt(key: any, value: any): boolean {
        return key.toString().startsWith('%') || key === 'this';
    }

    private processTypeClassSignature(value: any, typeClassSignature: any, objectNameArray: string[]
        , objectMethodNameArray: string[], classNameArray: string[], arkClass: ArkClass,
        fieldNameArray: string[], methodNameArray: string[], category: number): void {
        const name = value.getName();
        if (objectNameArray.includes(name)) {
            this.processUsedStatementsV(value, objectNameArray, objectMethodNameArray, category, arkClass);
        }

        const className = typeClassSignature.getClassName();
        if (classNameArray.includes(className)) {
            this.processUsedStatementsForClass(value, className, fieldNameArray, methodNameArray);
        }
    }

    private processUsedStatementsV(value: Local, objectNameArray: string[], objectMethodNameArray: string[], category: number, arkClass: ArkClass): void {
        const usedStmts = value.getUsedStmts() ?? [];
        for (const usedStmt of usedStmts) {
            if (!(usedStmt instanceof ArkAssignStmt)) {
                continue;
            }

            const leftOp = usedStmt.getLeftOp() as unknown as LeftOp;
            const leftOpName = leftOp.name;
            const rightOp = usedStmt.getRightOp() as unknown as LeftOp;
            const rightValue = rightOp.name;
            const LUsedStmts = leftOp.usedStmts ?? [];

            if (objectNameArray.includes(rightValue) && leftOpName.startsWith('%')) {
                this.processLUsedStmts(LUsedStmts, objectMethodNameArray, category, arkClass);
            }
        }
    }

    private processLUsedStmts(LUsedStmts: ArkAssignStmt[], objectMethodNameArray: string[], category: number, arkClass: ArkClass): void {
        for (const LUsedStmt of LUsedStmts) {
            const LeftOp = LUsedStmt.getLeftOp() as unknown as LeftOp;
            const RightOp = LUsedStmt.getRightOp() as unknown as stmtRightOp;
            const LeftOpName = LeftOp.name;
            const text = LUsedStmt.getOriginalText() ?? '';

            if (objectMethodNameArray.includes(LeftOpName)) {
                this.processMethodForCategory(LUsedStmt, text, arkClass, LeftOpName, category);
            } else {
                this.processFieldForCategory(LUsedStmt, text, arkClass, RightOp);
            }
        }
    }

    private processMethodForCategory(LUsedStmt: any, text: string, arkClass: ArkClass, LeftOpName: string, category: number): void {
        if (category === 5) {
            this.checkMethodWithCategory5(LUsedStmt, text, arkClass, LeftOpName);
        }
    }

    private processFieldForCategory(LUsedStmt: any, text: string, arkClass: ArkClass, RightOp: any): void {
        const fieldName = RightOp.fieldSignature.getFieldName();
        if (fieldName) {
            this.checkMethodForField(LUsedStmt, text, arkClass, fieldName);
        }
    }

    private checkMethodWithCategory5(LUsedStmt: any, text: string, arkClass: ArkClass, LeftOpName: string): void {
        // Perform method checking specific to category 5
        const methods = arkClass.getMethods();
        for (const method of methods) {
            this.processMethodF(LUsedStmt, text, LeftOpName, method);
        }
    }

    private checkMethodForField(LUsedStmt: any, text: string, arkClass: ArkClass, fieldName: string): void {
        // Perform field checking logic
        const methods = arkClass.getMethods();
        for (const method of methods) {
            this.processMethodForField(LUsedStmt, text, fieldName, method);
        }
    }

    private processMethodF(LUsedStmt: any, text: string, LeftOpName: string, method: any): void {
        // Process method logic
        const declareClass = method.getDeclaringArkClass();
        const arkFile = declareClass.getDeclaringArkFile();
        const methodSignature = method.getSignature();
        const methodSubSignature = methodSignature.getMethodSubSignature();
        const parameters = methodSubSignature.getParameters() ?? [];
        const hasThisVoid = this.checkMethodParameters(parameters);

        if (hasThisVoid || parameters.length === 0) {
            return;
        }
        this.addIssueReport(arkFile, LUsedStmt, text, LeftOpName);
    }

    private processMethodForField(LUsedStmt: any, text: string, fieldName: string, method: any): void {
        const declareClass = method.getDeclaringArkClass();
        const arkFile = declareClass.getDeclaringArkFile();
        this.addIssueReport(arkFile, LUsedStmt, text, fieldName);
    }

    private checkMethodParameters(parameters: any[]): boolean {
        let hasThisVoid = false;
        for (const parameter of parameters) {
            const parameterName = parameter.getName();
            const parameterType = parameter.getType();
            if (parameterName === 'this' && parameterType.toString() === 'void') {
                hasThisVoid = true;
            }
        }
        return hasThisVoid;
    }

    private processUsedStatementsForClass(value: Local, arkClass: ArkClass, fieldNameArray: string[], methodNameArray: string[]): void {
        const usedStmts = value.getUsedStmts() ?? [];
        for (const usedStmt of usedStmts) {
            if (!(usedStmt instanceof ArkAssignStmt)) {
                continue;
            }

            const text = usedStmt.getOriginalText() ?? '';
            const stmtRightOp = usedStmt.getRightOp() as unknown as stmtRightOp;
            const filedSignature = stmtRightOp.fieldSignature;

            if (filedSignature) {
                const stmtFiledName = filedSignature.getFieldName();
                if (fieldNameArray.includes(stmtFiledName)) {
                    continue;
                }

                if (methodNameArray.includes(stmtFiledName)) {
                    this.processMethodForField(usedStmt, text, stmtFiledName, arkClass.getMethods());
                }
            } else {
                this.processLeftOpForClass(usedStmt, arkClass, fieldNameArray, methodNameArray);
            }
        }
    }

    private processLeftOpForClass(usedStmt: ArkAssignStmt, arkClass: ArkClass, fieldNameArray: string[], methodNameArray: string[]): void {
        const leftOp = usedStmt.getLeftOp() as unknown as LeftOp;
        const LUsedStmts = leftOp.usedStmts ?? [];
        if (leftOp.toString().startsWith('%')) {
            for (const LUsedStmt of LUsedStmts) {
                const leftOpName = LUsedStmt.getLeftOp().toString();
                if (fieldNameArray.includes(leftOpName)) {
                    continue;
                }
                if (methodNameArray.includes(leftOpName)) {
                    this.processMethodForField(LUsedStmt, usedStmt.getOriginalText() ?? '', leftOpName, arkClass.getMethods());
                }
            }
        }
    }

    private processClass(
        targetClass: ArkClass,
        file: ArkFile,
        methods: ArkMethod[],
        classNameArray: string[],
        methodNameArray: string[],
        objectNameArray: string[],
        classes: ArkClass[],
        category: number,
        arkClass: ArkClass,
        objectMethodNameArray: string[],
        options: Options
    ): void {
        if (targetClass.getSignature().getClassName().startsWith('%')) {
            this.processClassName(
                targetClass,
                file,
                methods,
                classNameArray,
                methodNameArray,
                objectNameArray,
                objectMethodNameArray,
                classes,
                category,
                arkClass,
                options
            );
        }
    }

    private processClassName(
        targetClass: ArkClass,
        file: ArkFile,
        methods: ArkMethod[],
        classNameArray: string[],
        methodNameArray: string[],
        objectNameArray: string[],
        objectMethodNameArray: string[],
        classes: ArkClass[],
        category: number,
        arkClass: ArkClass,
        options: Options
    ): void {
        const defaultMethod = targetClass.getDefaultArkMethod();
        const stmts = defaultMethod?.getBody()?.getLocals() ?? [];
        for (const [key, value] of stmts.entries()) {
            if (key === 'this') {
                continue;
            }
            if (key.toString().startsWith('%')) {
                this.processDeclaringStatement(value, file, options, classes);
            } else {
                const declaringStmt = value.getDeclaringStmt();
                const text = declaringStmt?.getOriginalText() ?? '';
                const target = 'Promise.all';
                if (text.includes(target) && declaringStmt) {
                    this.addIssueReport(file, declaringStmt, text, target);
                }
            }
            this.processAssignStmtForObject(
                value,
                objectNameArray,
                category,
                arkClass,
                methods,
                classNameArray,
                methodNameArray,
                options
            );
        }
    }

    private processAssignStmtForObject(
        value: Local,
        objectNameArray: string[],
        category: number,
        arkClass: ArkClass,
        methods: ArkMethod[],
        classNameArray: string[],
        methodNameArray: string[],
        options: Options
    ): void {
        const type = value.getType() as unknown as stmtType;
        const typeClassSignature = type.classSignature;

        if (typeClassSignature) {
            const name = value.getName();
            if (objectNameArray.includes(name)) {
                this.handleObjectNameStatements(
                    value,
                    objectNameArray,
                    category,
                    arkClass,
                    methods,
                    methodNameArray
                );
            }

            const className = typeClassSignature.getClassName();
            if (classNameArray.includes(className)) {
                this.handleClassNameStatements(
                    value,
                    className,
                    methods,
                    methodNameArray
                );
            }
        } else {
            this.processStaticMethods(
                options, methods, classNameArray, methodNameArray, value
            );
        }
    }

    private handleObjectNameStatements(
        value: any,
        objectNameArray: string[],
        category: number,
        arkClass: any,
        methods: any[],
        methodNameArray: string[]
    ): void {
        const usedStmts = value.getUsedStmts() ?? [];
        for (const usedStmt of usedStmts) {
            if (usedStmt instanceof ArkAssignStmt) {
                const leftOp = usedStmt.getLeftOp() as unknown as LeftOp;
                const rightOp = usedStmt.getRightOp() as unknown as LeftOp;
                const LUsedStmts = leftOp.usedStmts ?? [];

                if (
                    objectNameArray.includes(rightOp.name) &&
                    leftOp.name.startsWith('%')
                ) {
                    this.processLUsedStatements(
                        LUsedStmts,
                        leftOp.name,
                        category,
                        arkClass,
                        methods,
                        methodNameArray
                    );
                }
            }
        }
    }

    private processLUsedStatements(
        LUsedStmts: any[],
        leftOpName: string,
        category: number,
        arkClass: any,
        methods: any[],
        methodNameArray: string[]
    ): void {
        for (const LUsedStmt of LUsedStmts) {
            const LeftOp = LUsedStmt.getLeftOp() as unknown as LeftOp;
            const LeftOpName = LeftOp.name;

            if (methodNameArray.includes(LeftOpName)) {
                if (category === 5) {
                    this.processMethodsForCategoryFive(methods, LUsedStmt, LeftOpName);
                }
            }
        }
    }

    private processMethodsForCategoryFive(
        methods: ArkMethod[],
        LUsedStmt: Stmt,
        LeftOpName: string
    ): void {
        for (const method of methods) {
            let hasThisVoid: boolean = false;
            const text = LUsedStmt.getOriginalText() ?? '';
            const declareClass = method.getDeclaringArkClass();
            const arkFile = declareClass.getDeclaringArkFile();
            const methodSignature = method.getSignature();
            const methodSubSignature = methodSignature.getMethodSubSignature();
            const parameters = methodSubSignature.getParameters() ?? [];

            this.processMethodsForCategoryFive1(
                parameters,
                arkFile,
                text,
                hasThisVoid,
                LUsedStmt,
                LeftOpName
            );
        }
    }
    private processMethodsForCategoryFive1(
        parameters: MethodParameter[],
        arkFile: ArkFile,
        text: string,
        hasThisVoid: boolean,
        LUsedStmt: Stmt,
        LeftOpName: string
    ): void {
        if (parameters.length === 0) {
            this.addIssueReport(arkFile, LUsedStmt, text, LeftOpName);
        } else {
            for (const parameter of parameters) {
                const parameterName = parameter.getName();
                const parameterType = parameter.getType();
                if (parameterName === 'this' && parameterType.toString() === 'void') {
                    hasThisVoid = true;
                }
            }
            if (!hasThisVoid) {
                this.addIssueReport(arkFile, LUsedStmt, text, LeftOpName);
            }
        }
    }
    private handleClassNameStatements(
        value: Local,
        className: string,
        methods: ArkMethod[],
        methodNameArray: string[]
    ): void {
        const usedStmts = value.getUsedStmts() ?? [];
        for (const usedStmt of usedStmts) {
            if (usedStmt instanceof ArkAssignStmt) {
                const text = usedStmt.getOriginalText() ?? '';
                const stmtRightOp = usedStmt.getRightOp() as unknown as stmtRightOp;
                const filedSignature = stmtRightOp.fieldSignature;

                this.handleClassNameStatements1(
                    filedSignature,
                    className,
                    methods,
                    methodNameArray,
                    usedStmt,
                    text
                );
            }
        }
    }

    private handleClassNameStatements1(
        filedSignature: FieldSignature,
        className: string,
        methods: ArkMethod[],
        methodNameArray: string[],
        usedStmt: ArkAssignStmt,
        text: string
    ): void {
        if (filedSignature) {
            const stmtFiledName = filedSignature.getFieldName();
            if (methodNameArray.includes(stmtFiledName)) {
                this.processMethodParametersForFieldSignature(
                    methods,
                    usedStmt,
                    className,
                    text
                );
            }
        } else {
            this.processLeftOpStatements(
                usedStmt,
                className,
                methods,
                methodNameArray
            );
        }
    }

    private processMethodParametersForFieldSignature(
        methods: ArkMethod[],
        usedStmt: ArkAssignStmt,
        className: string,
        text: string
    ): void {
        for (const method of methods) {
            const declareClass = method.getDeclaringArkClass();
            const arkFile = declareClass.getDeclaringArkFile();
            const methodSignature = method.getSignature();
            const MethodSubSignature = methodSignature.getMethodSubSignature();
            const parameters = MethodSubSignature.getParameters() ?? [];

            if (parameters.length > 0) {
                this.checkMethodParametersForVoidThis(
                    parameters,
                    method,
                    arkFile,
                    usedStmt,
                    text,
                    className
                );
            } else {
                this.checkTextForClassName(usedStmt, arkFile, text, className);
            }
        }
    }

    private checkMethodParametersForVoidThis(
        parameters: any[],
        method: any,
        arkFile: any,
        usedStmt: ArkAssignStmt,
        text: string,
        className: string
    ): void {
        for (const parameter of parameters) {
            const parameterName = parameter.getName();
            const parameterType = parameter.getType();
            if (parameterName === 'this' && parameterType.toString() === 'void') {
                continue;
            } else if (this.bindRegExpBy(text, `${className}`)) {
                continue;
            } else {
                this.checkTextForClassName(usedStmt, arkFile, text, className);
            }
        }
    }

    private checkTextForClassName(
        usedStmt: ArkAssignStmt,
        arkFile: ArkFile,
        text: string,
        className: string
    ): void {
        if (this.bindRegExp(text, `${className}`)) {
            return;
        } else {
            const rightOp = usedStmt.getRightOp() as unknown as stmtRightOp;
            const className = rightOp?.base?.name;
            const fieldName = rightOp?.fieldSignature?.getFieldName();
            const target = `${className}.${fieldName}`;
            if (text.includes(target)) {
                this.addIssueReport(arkFile, usedStmt, text, target);
            }
        }
    }

    private processLeftOpStatements(
        usedStmt: any,
        className: string,
        methods: any[],
        methodNameArray: string[]
    ): void {
        const leftOp = usedStmt.getLeftOp() as unknown as LeftOp;
        const LUsedStmts = leftOp.usedStmts ?? [];

        if (leftOp?.toString().startsWith('%')) {
            for (const LUsedStmt of LUsedStmts) {
                const leftOp = LUsedStmt.getLeftOp();
                const leftOpName = leftOp.toString();

                this.processLeftOpStatements1(
                    methodNameArray,
                    leftOpName,
                    methods,
                    LUsedStmt,
                    usedStmt
                );
            }
        }
    }
    private processLeftOpStatements1(methodNameArray: string[], leftOpName: string, methods: any[],
        LUsedStmt: ArkAssignStmt, usedStmt: any
    ): void {
        if (methodNameArray.includes(leftOpName)) {
            for (const method of methods) {
                const declareClass = method.getDeclaringArkClass();
                const arkFile = declareClass.getDeclaringArkFile();
                this.addIssueReport(
                    arkFile,
                    LUsedStmt,
                    usedStmt.getOriginalText() ?? '',
                    leftOpName
                );
            }
        }
    }
    private bindRegExpBy(text: string, pattern: string): boolean {
        // Check if a regular expression matches the text.
        return new RegExp(pattern).test(text);
    }

    private processDeclaringStatement(
        value: Local,
        file: ArkFile,
        options: Options,
        classes: ArkClass[]
    ): void {
        const declaringStmt = value.getDeclaringStmt();
        if (!(declaringStmt instanceof ArkAssignStmt)) {
            return;
        }
        let leftName = '';
        const text = declaringStmt.getOriginalText() ?? '';
        leftName = this.processLeftOperations(declaringStmt, file, text, classes);
        this.processFieldSignature(declaringStmt, file, text, options);
        this.processRightOperations(declaringStmt, value, file, text, leftName);
        this.processClassAssignments(declaringStmt, file, text);
    }

    private processStaticMethods(options: Options, methods: ArkMethod[],
        classNameArray: string[], methodNameArray: string[], value: Local): void {
        if (options.ignoreStatic === true) {
            this.processMethodsIgnoringStatic(methods, classNameArray, methodNameArray, value);
        } else {
            this.processMethodsIncludingStatic(methods, classNameArray, methodNameArray, value);
        }
    }

    private processMethodsIgnoringStatic(methods: any[], classNameArray: string[], methodNameArray: string[], value: any): void {
        for (const method of methods) {
            const declareClass = method.getDeclaringArkClass();
            const arkFile = declareClass.getDeclaringArkFile();
            const methodSignature = method.getSignature();
            const methodSubSignature = methodSignature.getMethodSubSignature();
            const staticFlag = methodSubSignature.isStatic();

            // Skip static methods
            if (staticFlag === true) {
                continue;
            }

            const declaringStmt = value.getDeclaringStmt();
            if (!(declaringStmt instanceof ArkAssignStmt)) {
                continue;
            }

            const rightOp = declaringStmt.getRightOp() as unknown as stmtRightOp;
            const leftOp = declaringStmt.getLeftOp() as unknown as LeftOp;
            const rightOpDeclaringStmt = rightOp?.base?.declaringStmt ?? [];

            // Skip if rightOpDeclaringStmt is not an ArkAssignStmt
            if (!(rightOpDeclaringStmt instanceof ArkAssignStmt)) {
                continue;
            }

            const Rright = rightOpDeclaringStmt.getRightOp();
            const text = rightOpDeclaringStmt.getOriginalText() ?? '';

            if (
                classNameArray.includes(Rright.toString()) &&
                methodNameArray.includes(leftOp.toString())
            ) {
                this.addIssueReport(arkFile, rightOpDeclaringStmt, text, leftOp.toString());
            }
        }
    }

    private processMethodsIncludingStatic(methods: any[], classNameArray: string[], methodNameArray: string[], value: any): void {
        for (const method of methods) {
            const declareClass = method.getDeclaringArkClass();
            const arkFile = declareClass.getDeclaringArkFile();
            const Value = value as unknown as LeftOp;
            const declaringStmt = Value.declaringStmt ?? [];

            if (!(declaringStmt instanceof ArkAssignStmt)) {
                continue;
            }

            const text = declaringStmt.getOriginalText() ?? '';
            const rightOp = declaringStmt.getRightOp() as unknown as fieldSignature;
            const leftOp = declaringStmt.getLeftOp() as unknown as LeftOp;
            const declaringSignature = rightOp?.fieldSignature?.getDeclaringSignature() as unknown as declaringSignature;
            const className = declaringSignature?.className;

            if (
                classNameArray.includes(className) &&
                methodNameArray.includes(leftOp.toString())
            ) {
                this.addIssueReport(arkFile, declaringStmt, text, leftOp.toString());
            }
        }
    }


    private processLeftOperations(
        declaringStmt: ArkAssignStmt,
        file: ArkFile,
        text: string,
        classes: ArkClass[]
    ): string {
        const LeftOp = declaringStmt.getLeftOp() as unknown as LeftOp;
        const RightOp = declaringStmt.getRightOp() as unknown as LeftOp;
        const rightOpName = RightOp.name;
        const usedStmts = LeftOp.usedStmts;
        let leftOpName = '';

        if (usedStmts && usedStmts.length > 0) {
            for (const usedStmt of usedStmts) {
                if (!(usedStmt instanceof ArkAssignStmt)) {
                    continue;
                }
                const leftOp = usedStmt.getLeftOp() as unknown as LeftOp;
                const constFlag = leftOp.constFlag;
                leftOpName = leftOp.name;
                if (constFlag && leftOpName && rightOpName && classes.length === 1) {
                    this.addIssueReport(file, declaringStmt, text, leftOpName);
                }
            }
        }
        return leftOpName;
    }

    private processFieldSignature(
        declaringStmt: any,
        file: any,
        text: string,
        options: any
    ): void {
        const RigOp = declaringStmt.getRightOp() as unknown as rightOpType;
        const fieldName = RigOp.fieldSignature?.getFieldName();
        const staticFlag = RigOp.fieldSignature?.isStatic();
        const DeclaringSignature =
            RigOp.fieldSignature?.getDeclaringSignature() as unknown as declaringSignature;
        const className = DeclaringSignature?.className;

        if (text.includes(fieldName) && text.includes(className) && staticFlag) {
            if (!options.ignoreStatic) {
                this.addIssueReport(file, declaringStmt, text, text);
            }
        }
    }

    private processRightOperations(
        declaringStmt: any,
        value: any,
        file: any,
        text: string,
        leftOpName: string
    ): void {
        const rightOp = declaringStmt.getRightOp() as unknown as stmtRightOp;
        if (rightOp.base && rightOp.fieldSignature) {
            this.processFieldUsage(
                declaringStmt,
                value,
                file,
                text,
                rightOp,
                leftOpName
            );
        } else {
            this.processClassAssignments(declaringStmt, file, text);
        }
    }

    private processFieldUsage(
        declaringStmt: Stmt,
        value: Local,
        file: ArkFile,
        text: string,
        rightOp: any,
        leftOpName: string
    ): void {
        const fieldSignature = rightOp?.fieldSignature;
        const fieldName = fieldSignature?.getFieldName();
        const DeclaringSignature =
            fieldSignature?.getDeclaringSignature() as unknown as declaringSignature;
        const className = DeclaringSignature?.className;
        const target = `${className}().${fieldName}`;
        const usedStmts = value.getUsedStmts();
        let FieldName;

        for (const usedStmt of usedStmts) {
            if (!(usedStmt instanceof ArkAssignStmt)) {
                continue;
            }
            const rightOp = usedStmt.getRightOp() as unknown as stmtRightOp;
            FieldName = rightOp?.fieldSignature?.getFieldName();
        }

        const target1 = `${className}.prototype.${FieldName}`;
        const target2 = `${className}.prototype`;
        const target3 = 'Promise.all';

        if (text.includes(target)) {
            this.addIssueReport(file, declaringStmt, text, text);
        }
        if (text.includes(target1) && className) {
            this.addIssueReport(file, declaringStmt, text, target1);
        }
        if (text.includes(target2) && className && leftOpName) {
            this.addIssueReport(file, declaringStmt, text, leftOpName);
        }
        if (text.includes(target3) && className) {
            this.addIssueReport(file, declaringStmt, text, target3);
        }
    }

    private processClassAssignments(
        declaringStmt: any,
        file: any,
        text: string
    ): void {
        const leftOp = declaringStmt.getLeftOp() as unknown as LeftOp;
        const rightOp = declaringStmt.getRightOp() as unknown as LeftOp;
        const FieldName = rightOp.type?.classSignature?.getClassName() ?? '';
        const usedStmts = leftOp.usedStmts;
        const arkClass = declaringStmt
            .getCfg()
            ?.getDeclaringMethod()
            ?.getDeclaringArkClass();
        const classes = arkClass.getDeclaringArkFile()?.getClasses();

        for (const [key, value] of classes.entries()) {
            const className = value.getSignature().getClassName();
            const code = value.getCode() ?? '';
            if (className.startsWith('%') || code.includes('=>')) {
                continue;
            }
            this.checkClassFields(
                value,
                file,
                declaringStmt,
                text,
                FieldName,
                usedStmts,
                className
            );
        }
    }

    private checkClassFields(
        value: any,
        file: any,
        declaringStmt: any,
        text: string,
        FieldName: string,
        usedStmts: any,
        className: string
    ): void {
        const fields = value.getFields();
        for (const [key, fieldValue] of fields.entries()) {
            const { fieldName, className: declaringClassName } = this.getFieldMetadata(fieldValue);
            const target = this.buildFieldTarget(className, fieldName);

            this.checkUsedStatementsForIssue(
                usedStmts,
                fieldName,
                FieldName,
                declaringClassName,
                file,
                declaringStmt,
                text
            );

            this.checkTextForTarget(target, text, file, declaringStmt);
        }
    }

    // 获取字段元数据（返回类型明确标注）
    private getFieldMetadata(fieldValue: any): {
        fieldName: string;
        className: string
    } {
        const fieldSignature = fieldValue.getSignature();
        const declaringSignature = fieldSignature.getDeclaringSignature() as unknown as declaringSignature;
        return {
            fieldName: fieldSignature.getFieldName(),
            className: declaringSignature.className
        };
    }

    // 构建字段目标字符串（返回类型明确标注）
    private buildFieldTarget(className: string, fieldName: string): string {
        return `new ${className}().${fieldName}`;
    }

    // 检查使用的语句是否符合条件（返回类型void）
    private checkUsedStatementsForIssue(
        usedStmts: any,
        fieldName: string,
        FieldName: string,
        declaringClassName: string,
        file: any,
        declaringStmt: any,
        text: string
    ): void {
        if (!usedStmts?.length) { return };

        for (const usedStmt of usedStmts) {
            if (!(usedStmt instanceof ArkAssignStmt)) { continue };

            const funName = usedStmt?.getLeftOp().toString();
            if (funName === fieldName && FieldName === declaringClassName) {
                this.addIssueReport(file, declaringStmt, text, funName);
            }
        }
    }

    // 检查文本是否包含目标字符串（返回类型void）
    private checkTextForTarget(
        target: string,
        text: string,
        file: any,
        declaringStmt: any
    ): void {
        if (text.includes(target)) {
            this.addIssueReport(file, declaringStmt, text, target);
        }
    }

    private processExtendedClasses(
        extendedClasses: Map<string, ArkClass>,
        ExtendmethodNameArray: string[],
        file: ArkFile,
        targetClass: ArkClass
    ): void {
        for (const [key, value] of extendedClasses.entries()) {
            if (!key || !value) {
                continue;
            }
            const methods = value.getMethods();
            if (!methods || methods.length === 0) {
                continue;
            }

            this.processExtendedClasses2(methods, ExtendmethodNameArray, file, targetClass);
        }
    }
    private processExtendedClasses1(stmts: Stmt[], ExtendmethodNameArray: string[],
        extendMethodName: string, file: ArkFile, targetClass: ArkClass
    ): void {
        for (const stmt of stmts) {
            const invokeExpr = CheckerUtils.getInvokeExprFromStmt(stmt);
            if (invokeExpr) {
                const methodName = invokeExpr
                    .getMethodSignature()
                    ?.getMethodSubSignature()
                    ?.getMethodName();
                if (methodName && !methodName.startsWith('%')) {
                    ExtendmethodNameArray.push(methodName);
                }
            }

            if (stmt instanceof ArkAssignStmt) {
                this.processAssignmentStmt(
                    stmt,
                    extendMethodName,
                    ExtendmethodNameArray,
                    file,
                    targetClass
                );
            }
        }
    }
    private processExtendedClasses2(methods: ArkMethod[], ExtendmethodNameArray: string[],
        file: ArkFile, targetClass: ArkClass
    ): void {
        for (const method of methods) {
            const extendMethodName = method
                .getSignature()
                .getMethodSubSignature()
                .getMethodName();
            const stmts = method.getBody()?.getCfg()?.getStmts() ?? [];

            this.processExtendedClasses1(
                stmts,
                ExtendmethodNameArray,
                extendMethodName,
                file,
                targetClass
            );
        }
    }
    private processAssignmentStmt(
        stmt: ArkAssignStmt,
        extendMethodName: string,
        ExtendmethodNameArray: string[],
        file: ArkFile,
        targetClass: ArkClass
    ): void {
        const text = stmt.getOriginalText() ?? '';
        const rightOp = stmt.getRightOp() as unknown as stmtRightOp;
        const baseName = rightOp.base?.name;
        const fieldName = rightOp.fieldSignature?.getFieldName();
        const methods = targetClass.getMethods();

        for (const ArkMethod of methods) {
            const methodName = ArkMethod.getSignature()
                .getMethodSubSignature()
                .getMethodName();
            if (methodName === extendMethodName) {
                continue;
            }
            if (
                ExtendmethodNameArray.includes(baseName) &&
                methodName === fieldName
            ) {
                this.addIssueReport(file, stmt, text, baseName);
            }
        }
    }

    private processMethods(
        methods: ArkMethod[],
        options: Options,
        file: ArkFile,
        fileds: ArkField[],
        methodNameArray: string[],
        fieldNameArray: string[]
    ): void {
        for (const method of methods) {
            this.processMethod(
                method,
                options,
                file,
                fileds,
                methodNameArray,
                fieldNameArray
            );
        }
    }

    private processMethod(
        method: ArkMethod,
        options: Options,
        file: ArkFile,
        fileds: ArkField[],
        methodNameArray: string[],
        fieldNameArray: string[]
    ): void {
        const methodSignature = method.getSignature();
        const methodSubSignature = methodSignature.getMethodSubSignature();
        const methodName = methodSubSignature.getMethodName();
        if (!methodName) { return };

        if (!methodName.startsWith('%')) {
            this.processRegularMethod(
                method,
                methodSubSignature,
                options,
                file,
                methodNameArray,
                fieldNameArray
            );
        } else {
            this.processSpecialMethod(
                method,
                fileds,
                methodNameArray,
                fieldNameArray
            );
        }
    }

    private processRegularMethod(
        method: ArkMethod,
        methodSubSignature: MethodSubSignature,
        options: Options,
        file: ArkFile,
        methodNameArray: string[],
        fieldNameArray: string[]
    ): void {
        const staticFlag = methodSubSignature.isStatic();
        if (options.ignoreStatic && staticFlag) { return };

        methodNameArray.push(methodSubSignature.getMethodName());
        this.processMethodParameters(
            method,
            methodSubSignature,
            file,
            fieldNameArray
        );
    }

    private processMethodParameters(
        method: ArkMethod,
        methodSubSignature: MethodSubSignature,
        file: ArkFile,
        fieldNameArray: string[]
    ): void {
        const parameters = methodSubSignature.getParameters();
        if (parameters.length === 0) { return };

        for (const parameter of parameters) {
            this.processMethodParameter(method, parameter, fieldNameArray, file);
        }
    }

    private processMethodParameter(
        method: ArkMethod,
        parameter: MethodParameter,
        fieldNameArray: string[],
        file: ArkFile
    ): void {
        const parameterTypeString = parameter.getType()?.getTypeString();
        if (!parameterTypeString?.includes('ContainsMethods')) { return };

        const locals = method.getBody()?.getLocals() ?? [];
        for (const [key, value] of locals.entries()) {
            if (value.getName() === parameter.getName()) {
                this.processUsedStatements(
                    file,
                    value.getUsedStmts(),
                    parameter.getName(),
                    fieldNameArray
                );
            }
        }
    }

    private processUsedStatements(
        file: ArkFile,
        usedStmts: Stmt[],
        parameterName: string,
        fieldNameArray: string[]
    ): void {
        let leftOpNameArray: string[] = [];

        for (const usedStmt of usedStmts) {
            if (!(usedStmt instanceof ArkAssignStmt)) { continue };

            const text = usedStmt.getOriginalText() ?? '';
            const leftOpName = usedStmt.getLeftOp()?.toString();
            if (leftOpNameArray.includes(leftOpName)) { continue };

            leftOpNameArray.push(leftOpName);
            this.analyzeStatementF(
                file,
                usedStmt,
                text,
                parameterName,
                fieldNameArray
            );
        }
    }

    private analyzeStatementF(
        file: ArkFile,
        usedStmt: ArkAssignStmt,
        text: string,
        parameterName: string,
        fieldNameArray: string[]
    ): void {
        const rightOp = usedStmt.getRightOp();
        const leftOp = usedStmt.getLeftOp();

        if (rightOp instanceof AbstractBinopExpr) {
            const baseName = (leftOp as unknown as stmtRightOp)?.base?.name;
            const fieldName = (
                leftOp as unknown as stmtRightOp
            )?.fieldSignature?.getFieldName();
            if (baseName === parameterName && fieldNameArray.includes(fieldName)) {
                this.addIssueReport(file, usedStmt, text, text);
            }
        } else {
            const baseName = (rightOp as unknown as stmtRightOp)?.base?.name;
            const fieldName = (
                rightOp as unknown as stmtRightOp
            )?.fieldSignature?.getFieldName();
            if (baseName === parameterName && fieldName) {
                fieldNameArray.push(fieldName);
                this.addIssueReport(file, usedStmt, text, text);
            }
        }
    }

    private processSpecialMethod(
        method: ArkMethod,
        fileds: ArkField[],
        methodNameArray: string[],
        fieldNameArray: string[]
    ): void {
        const code = method.getCode() ?? '';
        const regex1 = /\(\) => (.*)/;
        const match1 = code.match(regex1);
        const regex2 = /this\s*\.\s*\w+\(\)/;
        const match2 = code.match(regex2);

        if (match1 && !match2) {
            this.extractFieldNames(fileds, fieldNameArray);
        } else if (match1 && match2) {
            this.processSpecialMethodCalls(
                match2[0],
                fileds,
                methodNameArray,
                fieldNameArray
            );
        }
    }

    private processSpecialMethodCalls(
        match2Code: string,
        fileds: ArkField[],
        methodNameArray: string[],
        fieldNameArray: string[]
    ): void {
        const regex3 = /this\.(\w+)\(\)/;
        const match3 = match2Code.match(regex3);

        if (match3) {
            const match3Code = match3[1];
            if (methodNameArray.includes(match3Code)) {
                this.extractFieldNames(fileds, fieldNameArray);
            }
        }
    }

    private extractFieldNames(fileds: ArkField[], fieldNameArray: string[]): void {
        for (const arkField of fileds) {
            const fieldSignature = arkField.getSignature();
            const fieldName = fieldSignature.getFieldName();
            if (fieldName) {
                fieldNameArray.push(fieldName);
            }
        }
    }

    private processCategoryFive(
        arkClass: ArkClass,
        objectNameArray: string[],
        objectMethodNameArray: string[]
    ): void {
        this.collectObjectMethodNames(arkClass, objectMethodNameArray);
        this.collectObjectNames(arkClass, objectNameArray);
    }

    private collectObjectMethodNames(
        arkClass: ArkClass,
        objectMethodNameArray: string[]
    ): void {
        const methods = arkClass.getMethods();
        for (const method of methods) {
            const methodSignature = method.getSignature();
            const methodSubSignature = methodSignature.getMethodSubSignature();
            const methodName = methodSubSignature.getMethodName();
            if (methodName && !methodName.startsWith('%')) {
                objectMethodNameArray.push(methodName);
            }
        }
    }

    private collectObjectNames(
        arkClass: ArkClass,
        objectNameArray: string[]
    ): void {
        const declaringArkFile = arkClass.getDeclaringArkFile();
        const defaultClass = declaringArkFile.getDefaultClass();
        const defaultMethod = defaultClass.getDefaultArkMethod();
        const stmts = defaultMethod?.getBody()?.getLocals() ?? [];

        for (const [key, value] of stmts.entries()) {
            if (key.toString().startsWith('%') || key === 'this') {
                continue;
            }
            const type = value.getType() as unknown as stmtType;
            const classSignature = type.classSignature;
            if (classSignature) {
                const className = value.getName();
                const classSignatureName = classSignature.getClassName();
                if (classSignatureName.startsWith('%')) {
                    objectNameArray.push(className);
                }
            }
        }
    }

    private processImportsAndAnalyzeStatements(
        file: ArkFile,
        arkClass: ArkClass
    ): void {
        const importInfos = file.getImportInfos();
        if (!importInfos?.length) { return };

        for (const importInfo of importInfos) {
            const importClauseName = importInfo.getImportClauseName();
            const methods = arkClass.getMethods();

            this.processImportsAndAnalyzeStatements1(
                file,
                methods,
                importClauseName
            );
        }
    }

    private processImportsAndAnalyzeStatements1(
        file: ArkFile,
        methods: ArkMethod[],
        importClauseName: string
    ): void {
        for (const arkMethod of methods) {
            const stmts = arkMethod.getBody()?.getCfg()?.getStmts() ?? [];
            for (const stmt of stmts) {
                if (!(stmt instanceof ArkAssignStmt)) { continue };
                this.analyzeStatement(file, stmt, importClauseName);
            }
        }
    }

    private analyzeStatement(
        file: ArkFile,
        stmt: ArkAssignStmt,
        importClauseName: string
    ): void {
        const text = stmt.getOriginalText();
        if (!text) { return };

        const rightOp = stmt.getRightOp() as unknown as stmtRightOp;
        const leftOp = stmt.getLeftOp() as unknown as LeftOp;
        const usedStmts = leftOp.usedStmts;

        if (usedStmts?.length) {
            this.analyzeUsedStatements(
                file,
                stmt,
                text,
                rightOp,
                usedStmts,
                importClauseName
            );
        }

        const fieldName = rightOp?.fieldSignature?.getFieldName();
        if (fieldName) {
            const target = `${importClauseName}.${fieldName}`;
            if (text.includes(target)) {
                this.addIssueReport(file, stmt, text, target);
            }
        }
    }

    private analyzeUsedStatements(
        file: ArkFile,
        stmt: ArkAssignStmt,
        text: string,
        rightOp: stmtRightOp,
        usedStmts: ArkAssignStmt[],
        importClauseName: string
    ): void {
        for (const usedStmt of usedStmts) {
            if (!(usedStmt instanceof ArkAssignStmt)) { continue };

            const leftOpStr = usedStmt.getLeftOp()?.toString();
            if (leftOpStr && rightOp.toString() !== importClauseName) {
                if (usedStmts.length > 1 && usedStmts[0] instanceof ArkAssignStmt) {
                    const LeftOpName = usedStmts[0].getLeftOp()?.toString();
                    this.addIssueReport(file, stmt, text, LeftOpName);
                } else if (!(text.includes(':') && text.includes(leftOpStr))) {
                    this.addIssueReport(file, stmt, text, leftOpStr);
                }
            }
        }
    }

    private bindRegExp(text: string, bindParameter: string): boolean {
        // 动态构建正则表达式，将 bindParameter 插入到捕获组中
        const regex = new RegExp(
            `\\bconst\\s+\\w+\\s*=\\s*\\w+\\.\\w+\\.bind\\((${bindParameter})\\)\\s*`
        );
        return regex.test(text);
    }
    private addIssueReport(
        arkFile: ArkFile,
        stmt: Stmt,
        name: string,
        targetName: string
    ): void {
        const severity = this.rule.alert ?? this.metaData.severity;
        const warnInfo = this.getLineAndColumn(arkFile, stmt, name, targetName);
        if (warnInfo) {
            this.metaData.description = this.metaData.description.padEnd(130);
            const filePath = arkFile.getFilePath();
            let defects = new Defects(
                warnInfo.line,
                warnInfo.startCol,
                warnInfo.endCol,
                this.metaData.description,
                severity,
                this.rule.ruleId,
                filePath,
                this.metaData.ruleDocPath,
                true,
                false,
                false
            );
            this.issues.push(new IssueReport(defects, undefined));
            RuleListUtil.push(defects);
        } else {
            logger.debug('No valid line number found for issue report.');
        }
    }
    private getLineAndColumn(
        arkfile: ArkFile,
        stmt: Stmt,
        name: string,
        targetName: string
    ): {
        line: number;
        startCol: number;
        endCol: number;
        filePath: string;
    } | null {
        if (!arkfile) {
            logger.debug('originStmt or arkFile is null');
            return null;
        }

        const { lines, lineNumber } = this.getCodeLinesAndLineNumber(arkfile, stmt);
        return this.processLines(lines, lineNumber, arkfile, name, targetName);
    }

    private getCodeLinesAndLineNumber(arkfile: ArkFile, stmt: Stmt): { lines: string[]; lineNumber: number; } {
        const code = arkfile.getCode() ?? '';
        const lines = code.split('\r\n');
        const originPosition = stmt.getOriginPositionInfo();
        const lineNumber = originPosition.getLineNo();
        return { lines, lineNumber };
    }

    private processLines(
        lines: string[],
        lineNumber: number,
        arkfile: ArkFile,
        name: string,
        targetName: string
    ): { line: number; startCol: number; endCol: number; filePath: string; } | null {
        for (const line of lines) {
            const result = this.processSingleLine(line, name, targetName);
            if (result) {
                return this.createPositionResult(lineNumber, result.index, arkfile);
            }
        }
        return null;
    }

    private processSingleLine(line: string, name: string, targetName: string): { index: number; } | null {
        const lineIndex = line.indexOf(name);
        if (lineIndex === -1 || line.startsWith('//')) {
            return null;
        }

        const targetIndex = line.indexOf(targetName);
        return targetIndex !== -1 ? { index: targetIndex } : null;
    }

    private createPositionResult(
        lineNumber: number,
        targetIndex: number,
        arkfile: ArkFile
    ): { line: number; startCol: number; endCol: number; filePath: string; } {
        return {
            line: lineNumber,
            startCol: targetIndex + 1,
            endCol: targetIndex + 1,
            filePath: arkfile.getFilePath()
        };
    }
}